﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Sofire.Serialization;
using EnvDTE;
using SofireXSqlEntityGenerator.Core;
using System.Xml;

namespace SofireXSqlEntityGenerator
{
    /// <summary>
    /// 全局配置。
    /// </summary>
    public class GlobalSetting
    {
        static GlobalSetting()
        {
            if(File.Exists(GlobalSettingPath))
            {
                var r = Serializer.Read<GlobalSetting>(GlobalSettingPath);
                if(r.IsSucceed) _Current = r.Value;
            }
            else
            {
                _Current = new GlobalSetting();
            }
        }

        private readonly static FastBinarySerializer Serializer = new FastBinarySerializer();
        private readonly static string GlobalSettingPath = Path.Combine(GA.AppDirectory, "Global.Setting");
        private readonly static GlobalSetting _Current;

        private GlobalSetting() { }

        private bool _AutoAliasName = false;
        /// <summary>
        /// 设置或获取一个值，指示是否自动识别名称。默认为 false。
        /// </summary>
        public static bool AutoAliasName
        {
            get
            {
                return _Current._AutoAliasName;
            }
            set
            {
                _Current._AutoAliasName = value;
            }
        }

        private bool _AlwaysNullable = true;
        /// <summary>
        /// 设置或获取一个值，指示无论数据库字段类型是否允许为空，都采用可空类型。默认为 true。
        /// </summary>
        public static bool AlwaysNullable
        {
            get
            {
                return _Current._AlwaysNullable;
            }
            set
            {
                _Current._AlwaysNullable = value;
            }
        }

        private string _ModelSuffix = "Model";
        /// <summary>
        /// 设置或获取实体的默认后缀名。
        /// </summary>
        public static string ModelSuffix
        {
            get
            {
                return _Current._ModelSuffix;
            }
            set
            {
                _Current._ModelSuffix = value;
            }
        }

        private string _TemplatesDirectory = GA.AppDirectory + "Templates\\Default";
        /// <summary>
        /// 设置或获取模板的目录。
        /// </summary>
        public static string TemplatesDirectory
        {
            get
            {
                return _Current._TemplatesDirectory;
            }
            set
            {
                _Current._TemplatesDirectory = value;
            }
        }

        private string _XSqlDirectory = "\\XSqls";
        /// <summary>
        /// 设置或获取默认 XSql 的目录。
        /// </summary>
        public static string XSqlDirectory
        {
            get
            {
                return _Current._XSqlDirectory;
            }
            set
            {
                _Current._XSqlDirectory = value;
            }
        }

        private string _XSqlSettingName = "xsql.setting";
        public static string XSqlSettingName
        {
            get
            {
                return _Current._XSqlSettingName;
            }
            set
            {
                _Current._XSqlSettingName = value;
            }
        }
        public static string GetXSqlDirectory()
        {
            if(string.IsNullOrEmpty(_Current._XSqlDirectory)) _Current._XSqlDirectory = "\\XSqls";

            if(_Current._XSqlDirectory.StartsWith("\\"))
            {
                return Path.Combine(GlobalParameters.ProjectDirectory, _Current._XSqlDirectory.Remove(0, 1));
            }
            return Path.Combine(GlobalParameters.OutputDirectory, _Current._XSqlDirectory);

        }

        private bool _EnabledXSql = true;
        /// <summary>
        /// 设置或获取一个值，指示是是否启用 XSql。默认为 true。
        /// </summary>
        public static bool EnabledXSql
        {
            get
            {
                return _Current._EnabledXSql;
            }
            set
            {
                _Current._EnabledXSql = value;
            }
        }

        public static void Save()
        {
            Serializer.Write(GlobalSettingPath, _Current);
        }
    }

    public class GlobalParameters
    {
        /// <summary>
        /// 获取选中项的输出目录。
        /// </summary>
        public static string OutputDirectory;
        /// <summary>
        /// 获取项目的命名空间。
        /// </summary>
        public static string Namespace;
        /// <summary>
        /// 获取项目的根目录。
        /// </summary>
        public static string ProjectDirectory;

        /// <summary>
        /// 获取选中的第一个项目。
        /// </summary>
        public static Project SelectedProject;

        public static void Init()
        {
            GlobalParameters.SelectedProject = Connect.ApplicationObject.GetSelectingProject(out GlobalParameters.OutputDirectory, out GlobalParameters.Namespace);
            if(GlobalParameters.SelectedProject != null)
            {
                ProjectDirectory = Path.GetDirectoryName(GlobalParameters.SelectedProject.FullName);
            }
        }
    }

    public static class GlobalActions
    {
        public static void Write(this EntityGenerator generator, string codeFilename, string xsqlFilename, bool openFile)
        {
            string entityCode, xsqlCode;
            generator.Create(out entityCode, out xsqlCode, xsqlFilename != null);
            Write(codeFilename, entityCode, openFile, false);
            if(xsqlFilename == null) return;
            Write(xsqlFilename, xsqlCode, openFile, true);
            var settingPath = Path.Combine(Path.GetDirectoryName(xsqlFilename), "xsql.setting");
            XmlDocument document = new XmlDocument();
            XmlNode documentElement;
            bool createAndAppend = false;
            if(File.Exists(settingPath))
            {
                document.Load(settingPath);
                documentElement = document.DocumentElement;
            }
            else
            {
                createAndAppend = true;
                documentElement = document.AppendChild(document.CreateElement("setting"));
            }
            var fullClass = GlobalParameters.Namespace + "." + generator.ClassName;
            XmlElement element;
            foreach(XmlNode node in documentElement.ChildNodes)
            {
                if(node.TryGetAttribute("type") == fullClass)
                {
                    element = node as XmlElement;
                    element.RemoveAttribute("path");
                    goto FINDED;
                }
            }
            element = document.CreateElement("xsql");
            documentElement.AppendChild(element);
            var typeAttribute = document.CreateAttribute("type");
            typeAttribute.Value = fullClass;
            element.Attributes.Append(typeAttribute);
        FINDED:

            var pathAttribute = document.CreateAttribute("path");
            pathAttribute.Value = Path.GetFileName(xsqlFilename);
            element.Attributes.Append(pathAttribute);
            document.Save(settingPath);
            if(createAndAppend)
            {
                var file = GlobalParameters.SelectedProject.ProjectItems.AddFromFile(settingPath);
                file.Properties.Item("CopyToOutputDirectory").Value = (int)CopyToOutputDirectory.CopyAlways;
            }
            // 增加对 xsql.setting 的 add 
            // type = "XSqlFormDemo.Models.UsersModel" path="UserChatsModel.xsql"

            //var project = (GlobalParameters.SelectedProject.Object as VSLangProj.VSProject);
            //if(project == null) throw new Exception("VSProject is null");

            // project.References.Add("");
        }
        /// <summary>
        /// Defines if and when a file is copied to the output directory.
        /// </summary>
        public enum CopyToOutputDirectory
        {
            /// <summary>
            /// Do not copy this file to the output directory.
            /// </summary>
            DoNotCopy = 0,

            /// <summary>
            /// Always copy this file to the output directory.
            /// </summary>
            CopyAlways = 1,

            /// <summary>
            /// Copy this file to the output directory only if it is 
            /// newer than the same file in the output directory.
            /// </summary>
            CopyIfNewer = 2,
        }
        /// <summary>
        /// Defines the known Build Actions for Visual Studio project items.
        /// </summary>
        public static class BuildAction
        {
            /// <summary>
            /// No action is taken.
            /// </summary>
            public const string None = "None";

            /// <summary>
            /// The file is compiled.
            /// </summary>
            public const string Compile = "Compile";

            /// <summary>
            /// The file is included in the Content project output group.
            /// </summary>
            public const string Content = "Content";

            /// <summary>
            /// The file is included in the main generated assembly or in a satellite assembly as a resource.
            /// </summary>
            public const string EmbeddedResource = "EmbeddedResource";
        }

        private static void Write(string filename, string content, bool openFile, bool outputFile)
        {

            var dire = Path.GetDirectoryName(filename);
            if(!Directory.Exists(dire))
            {
                // GlobalParameters.SelectedProject.ProjectItems.AddFolder(dire);
                Directory.CreateDirectory(dire);
                //foreach(ProjectItem item in GlobalParameters.SelectedProject.ProjectItems)
                //{
                //    if(string.Equals(item.Name,dire))
                //}
                GlobalParameters.SelectedProject.ProjectItems.AddFromDirectory(dire);
            }

            File.WriteAllText(filename, content, Encoding.Default);

            var file = GlobalParameters.SelectedProject.ProjectItems.AddFromFile(filename);
            if(outputFile) file.Properties.Item("CopyToOutputDirectory").Value = (int)CopyToOutputDirectory.CopyAlways;
            if(openFile)
            {
                Connect.ApplicationObject.ItemOperations.OpenFile(filename, file.Kind);
                Connect.ApplicationObject.MainWindow.SetFocus();
            }

        }
    }
}
